import utilsType from './type'
import utilsNumber from './number'
import regUtils from './reg'
// 数组去重  by shw
const arrDedup = function <K> (arr: K[] = []): K[] {
	return Array.from(new Set(arr))
}
// 查找数组满足条件的元素,且返回指定值  by shw
const appointedMap = function <K> (arr = [], filter: Function): K[] {
	const res: K[] = []
	arr.forEach((item, i) => {
		const data = filter(item, i)
		if (undefined !== data) {
			res.push(data)
		}
	})
	return res
}
// 数组求和 by shw
type ToNumberFunction<K> = (arg: K) => number | string
const arrSum = function <K> (arr: K[] = [], fn: ToNumberFunction<K>, decimal = 2): string {
	const sum = arr.reduce((pre, cur) => {
		return utilsNumber.toNumber(pre) + utilsNumber.toNumber(fn(cur))
	}, 0)
	return utilsNumber.toFixed(sum, decimal)
}
// 数组扁平化 by shw
const arrFlatten = function <T extends Object, K extends Object> (arr: T[], fn: Function, recursive = true): K[] {
	return arr.reduce((pre, cur) => {
		const child = fn(cur)
		if (Array.isArray(child) && recursive) {
			const list = arrFlatten(child as [], fn)
			const curList = [cur].concat(list as [])
			return pre.concat(curList as [])
		} else {
			return pre.concat(child)
		}
	}, [])
}
// 数组删除
const arrRemove = function <T> (arr: never[], key: string | never[]): T[] | undefined {
	if (utilsType.toRawType(key) === 'String') {
		return arr.filter(item => {
			return item !== key
		})
	} else if (utilsType.toRawType(key) === 'Array') {
		return arr.filter(item => {
			return !key.includes(item)
		})
	}
}
// 判断是空数组
const isArrayEmpty = function (arr: never[]): boolean {
	return Array.isArray(arr) && arr.length === 0
}
/**
 * 数组排序
 * @param name key
 * @param order asc 升序，des 降序
 * @param minor 排序函数
 */
const sortBy = function (name: string, order = 'asc', minor: Function): Function {
	const rev = order === 'asc' ? 1 : -1
	return function (o: string | { [key: string]: unknown }, p: string | { [key: string]: unknown }) {
		if (o && p && typeof o === 'object' && typeof p === 'object') {
			const a: string = (utilsType.getObjDeepValue(o, name))
			const b: string = (utilsType.getObjDeepValue(p, name))
			if (a === b) {
				return typeof minor === 'function' ? minor(o, p) : 0
			}
			if (regUtils.regInitByType('chinese').test(a[0]) && !regUtils.regInitByType('chinese').test(b[0])) {
				return 1 * rev
			}
			if (!regUtils.regInitByType('chinese').test(a[0]) && regUtils.regInitByType('chinese').test(b[0])) {
				return -1 * rev
			}
			if (typeof a === 'string') {
				return a.localeCompare(b) * rev
			}
			return parseFloat(a) < parseFloat(b) ? -1 * rev : 1 * rev
		}
	}
}
/**
 * 获取数组最大属性
 */
type FindMaxCallBack<K> = (arg: K) => number
const findMax = <K> (arr: K[], fn: FindMaxCallBack<K>): number | null => {
	let max: null | number = null
	arr.forEach(item => {
		const result = fn(item)
		if (max === null) {
			max = result
		} else {
			if (result > max) {
				max = result
			}
		}
	})
	return max
}
/**
 * 数组递归查找
 */
const findRecursion = <T> (arr: T[], fn: (arg: T) => boolean, childKey: string): T | undefined => {
	for (let i = 0; i < arr.length; i++) {
		const item = arr[i]
		const result = fn(item)
		if (result) {
			return item
		}
		if (Array.isArray(item[childKey as keyof T])) {
			const node = findRecursion(item[childKey as keyof T] as unknown as T[], fn, childKey)
			if (node) {
				return node
			}
		}
	}
}

export default {
	arrDedup,
	appointedMap,
	arrSum,
	arrFlatten,
	arrRemove,
	isArrayEmpty,
	sortBy,
	findMax,
	findRecursion
}
